package com.aecc.api.apivalid;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.bouncycastle.util.encoders.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.aecc.api.config.CustomEncryptPropertity;
import com.aecc.api.model.RequestModel;
import com.aecc.api.model.ResultModel;
import com.aecc.api.model.TokenEntity;
import com.aecc.api.util.JSONUtil;
import com.fasterxml.jackson.core.JsonProcessingException;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import cn.hutool.crypto.symmetric.SymmetricCrypto;

@Aspect
@Component
public class RequestAop {
	@Autowired
	private CustomEncryptPropertity encryptPropertity;
	
	@Around(value = "@annotation(com.aecc.api.apivalid.RequestCheck)")
	public Object checkRequest(ProceedingJoinPoint joinPoint) throws Throwable {
		RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
        HttpServletRequest request = servletRequestAttributes.getRequest();
        HttpServletResponse response = servletRequestAttributes.getResponse();
        // 校验token
        String token = request.getHeader("Token");
        if(StringUtils.isBlank(token)) {            
        	returnData(response, ResultModel.custom(-1, "非法请求：token不存在"));
        	return null;
        }
        // 解密token
        SymmetricCrypto sm4 = SmUtil.sm4(Base64.decode(encryptPropertity.getSm4Key()));
        TokenEntity tokenEntity;
        try {
        	tokenEntity = JSONUtil.parseObject(sm4.decryptStr(token, CharsetUtil.CHARSET_UTF_8), TokenEntity.class);
        } catch (Exception e) {
        	returnData(response, ResultModel.custom(-1, "非法请求：校验token失败"));
        	return null;
		}
        // 校验token是否过期
        if(LocalDateTime.now().isAfter(tokenEntity.getExpTime())) {
        	returnData(response, ResultModel.custom(-1, "token已过期，请重新获取token"));
        	return null;
        }
        String method = request.getMethod();
        Object[] args = joinPoint.getArgs();
        if(StringUtils.equalsIgnoreCase(method, "POST") && args.length > 0) {
        	RequestModel rm = (RequestModel)joinPoint.getArgs()[0];
        	if(StringUtils.isBlank(rm.getSignature())) {
        		returnData(response, ResultModel.fail("参数signature不能为空"));
        		return null;
        	}
        	if(rm.getEncrypt() == null || (rm.getEncrypt() != 0 && rm.getEncrypt() != 1)) {
        		returnData(response, ResultModel.fail("参数encrypt不正确"));
        		return null;
        	}
        	if(rm.getEncrypt() == 1 && StringUtils.isBlank(rm.getEncryptKey())) {
        		returnData(response, ResultModel.fail("密文传输模式参数encryptKey不能为空"));
        		return null;
        	}
        	String signValidStr = tokenEntity.getKey();
        	// 密文传输
        	if(rm.getEncrypt() == 1) {
        		// 解密秘钥
        		try {
        			SM2 sm2 = SmUtil.sm2(tokenEntity.getPrivateKey(), null);
        			byte[] dataSM4Key = sm2.decrypt(rm.getEncryptKey(), KeyType.PrivateKey);
            		SymmetricCrypto dataSm4 = SmUtil.sm4(dataSM4Key);
            		String dataListJson = dataSm4.decryptStr(rm.getDataList().toString(), CharsetUtil.CHARSET_UTF_8);
            		signValidStr += dataListJson;
            		rm.setDataList(JSONUtil.parseObject(dataListJson, List.class));
				} catch (Exception e) {
					returnData(response, ResultModel.fail("数据解密异常"));
					return null;
				}
        	}else {
        		signValidStr += JSONUtil.toJSONString(rm.getDataList());
        	}
        	// 校验签名
        	if(!StringUtils.equals(rm.getSignature(), SmUtil.sm3(signValidStr))) {
        		returnData(response, ResultModel.fail("数据签名校验失败"));
        		return null;
        	}
        }
		return joinPoint.proceed(joinPoint.getArgs());
	}
	
	private void returnData(HttpServletResponse response, ResultModel res) throws JsonProcessingException, IOException {
		response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        response.getWriter().println(JSONUtil.toJSONString(res));
	}
}
